package com.upbos.sso.plugin;

import cn.hutool.core.util.NumberUtil;
import com.upbos.core.ret.RetCode;
import com.upbos.core.ret.RetData;
import com.upbos.sso.entity.SsoContext;
import com.upbos.sso.filter.ChainRet;
import com.upbos.sso.Constants;
import com.upbos.sso.util.ServletUtils;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <b>Application name：</b> TokenValidateInterceptor.java <br>
 * <b>Application describing： 校验Token是否有效 </b> <br>
 * <b>Copyright：</b> Copyright &copy; 2018 upbos.com 版权所有。<br>
 * <b>Company：</b> upbos.com <br>
 * <b>Date：</b> 2018年09月24日 12:42 <br>
 * <b>author：</b> <a href="mailto:wangjz@miyzh.com"> wangjz </a> <br>
 * <b>version：</b>V1.0.0 <br>
 */
public class TokenInterceptor implements Interceptor {

    /**
     * 会话过期页面列表，每个url用->分割，前半部分指匹配的路径，后半部指会话失效后跳转的页面，数字代表登录页面列表的序号，否则，代表失效页面url
     * 例如:
     * - /upm/**->0
     * - /weixin/**->1
     */
    private List<String> expireUrls = new ArrayList<>(Arrays.asList("/**/*->0"));

    private List<String[]> parseExpireUrls;

    /**
     * 设置会话失效跳转地址
     *
     * @param expireUrl
     */
    public void setExpireUrl(String expireUrl) {
        this.expireUrls.clear();
        this.expireUrls.add("/**/*->" + expireUrl);
    }

    /**
     * 设置会话失效跳转地址列表
     *
     * @param expireUrls
     */
    public void setExpireUrls(List<String> expireUrls) {
        this.expireUrls = expireUrls;
    }

    private List<String[]> parseExpireUrl(SsoContext ssoContext) {
        if (parseExpireUrls != null) {
            return parseExpireUrls;
        }
        parseExpireUrls = new ArrayList<>();
        for (String url : this.expireUrls) {
            String[] splitUrl = url.split("->");
            String pattern = splitUrl[0].trim();
            String expireUrl = splitUrl[1].trim();
            if (NumberUtil.isNumber(expireUrl)) {
                int pos = Integer.parseInt(expireUrl) >= ssoContext.getLoginUrls().size() ? ssoContext.getLoginUrls().size() : Integer.parseInt(expireUrl);
                expireUrl = ssoContext.getLoginUrls().get(pos);
            }
            parseExpireUrls.add(new String[]{pattern, expireUrl});
        }
        return parseExpireUrls;
    }


    @Override
    public ChainRet preHandle(HttpServletRequest request, HttpServletResponse response, SsoContext ssoContext) {

        String requestUri = request.getRequestURI();
        PathMatcher matcher = new AntPathMatcher();

        // 放行登录页面loginUrls
        if (matchIndex(request, ssoContext.getLoginUrls(), matcher) > -1) {
            return ChainRet.SKIP;
        }

        // 放行会话过期页面expireUrls
        List<String[]> parseExpireUrls = parseExpireUrl(ssoContext);
        for (String[] parseExpireUrl : parseExpireUrls) {
            if (matcher.match(parseExpireUrl[1], requestUri)) {
                return ChainRet.SKIP;
            }
        }

        // 验证会话是否有效
        if (ssoContext.getSsoManager().validateToken(request)) {
            return ChainRet.NEXT;
        }

        //session不存在，重新定向session失效页面
        RetData retData = new RetData(RetCode.TOKEN_EXPIRE);
        if (ServletUtils.isAjax(request)) {
            ServletUtils.write(response, retData);
            return ChainRet.BREAK;
        }

        for (String[] parseExpireUrl : parseExpireUrls) {
            if (matcher.match(parseExpireUrl[0], requestUri)) {
                ServletUtils.sendRedirect(response, parseExpireUrl[1]);
                break;
            }
        }

        return ChainRet.BREAK;
    }

    /**
     * 拦截器执行优先级
     *
     * @return
     */
    @Override
    public int getPriority() {
        return 1;
    }

    @Override
    public String getName() {
        return Constants.INTERCEPTOR_TOKEN;
    }

}
